#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <sstream>
#include <functional>
#include <vector>
#include <fstream>
#include <unordered_map>

using std::cout;
using std::endl;
using std::string;

const static string base_sep = "\r\n";
const static string line_sep = ": ";
const static string prefixpath = "wwwroot"; // web根目录
const static string arg_sep = "?";          // url的参数分隔符
const static string suffixsep = ".";        // 文件后缀分隔符
const static string homepage = "index.html";

const static string spacesep = " ";
const static string httpversion = "HTTP/1.0"; // 默认HTTP版本
const static string html_404 = "404.html";

class HttpRequest
{
private:
    string GetLine(string &reqstr) // 获取第一行字符串
    {
        auto pos = reqstr.find(base_sep);
        if (pos == string::npos)
        {
            return string();
        }

        string line = reqstr.substr(0, pos);
        reqstr.erase(0, line.size() + base_sep.size());
        return line.empty() ? base_sep : line;
    }

    void ParseReqLine() // 分离请求行的各个字段
    {
        std::stringstream ss(_req_line);
        ss >> _method >> _url >> _version;
        if (strcasecmp(_method.c_str(), "GET") == 0) // GET请求的URL携带参数，需要分离
        {
            auto pos = _url.find(arg_sep);
            if (pos != string::npos)
            {
                _body_text = _url.substr(pos + arg_sep.size()); // 将参数信息放在请求体中
                _url.resize(pos);
            }
        }
        // 获得资源最终在服务端的绝对路径
        _path += _url;
        if (_path[_path.size() - 1] == '/') // 绝对路径是一个目录的话就添加一个默认资源
        {
            _path += homepage;
        }
        auto pos = _path.rfind(suffixsep); // rfind从右侧开始查找
        if (pos != string::npos)
        {
            _suffix = _path.substr(pos);
        }
        else
        {
            _suffix = ".default";
        }
    }

    void ParseReqHeader() // 分离报头的各个字段
    {
        for (auto &header : _req_headers)
        {
            auto pos = header.find(line_sep);
            if (pos == string::npos)
            {
                continue;
            }
            string k = header.substr(0, pos);
            string v = header.substr(pos + line_sep.size());
            if (k.empty() || v.empty())
            {
                continue;
            }
            _headers_kv[k] = v;
        }
    }

public:
    HttpRequest()
        : _blank_line(base_sep), _path(prefixpath)
    {
    }

    void Deserialize(string &reqstr)
    {
        // 基本反序列化
        _req_line = GetLine(reqstr); // 首行是请求行
        string header;
        do
        {
            header = GetLine(reqstr);
            if (header.empty())
                break;
            else if (header == base_sep)
                break;
            _req_headers.push_back(header);
        } while (true);
        if (!reqstr.empty())
        {
            _body_text = reqstr;
        }
        // 进一步反序列化
        ParseReqLine();   // 提取请求行中的有效字段
        ParseReqHeader(); // 提取出报文中的有效字段
    }
    // 提供获取请求报文信息的一些接口
    std::string Url()
    {
        LOG(DEBUG, "Client Want url %s\n", _url.c_str());
        return _url;
    }
    std::string Path()
    {
        LOG(DEBUG, "Client Want path %s\n", _path.c_str());
        return _path;
    }
    std::string Suffix()
    {
        return _suffix;
    }
    std::string Method()
    {
        LOG(DEBUG, "Client request method is %s\n", _method.c_str());
        return _method;
    }
    std::string GetResuestBody()
    {
        LOG(DEBUG, "Client request method is %s, args: %s, request path: %s\n",
            _method.c_str(), _body_text.c_str(), _path.c_str());
        return _body_text;
    }

    void Print() // 格式化输出反序列化后的信息
    {
        std::cout << "----------------------------" << std::endl;
        std::cout << "###" << _req_line << std::endl;
        for (auto &header : _req_headers)
        {
            std::cout << "@@@" << header << std::endl;
        }
        std::cout << "***" << _blank_line;
        std::cout << ">>>" << _body_text << std::endl;

        std::cout << "Method: " << _method << std::endl;
        std::cout << "Url: " << _url << std::endl;
        std::cout << "Version: " << _version << std::endl;

        for (auto &header_kv : _headers_kv)
        {
            std::cout << ")))" << header_kv.first << "->" << header_kv.second << std::endl;
        }
    }

private:
    // 基本http请求格式
    std::string _req_line;                 // 请求行
    std::vector<std::string> _req_headers; // 请求报头
    std::string _blank_line;               // 空行
    std::string _body_text;                // 请求体

    // 更具体的属性字段，需要进一步反序列化
    std::string _method;                                      // 请求方法
    std::string _url;                                         // url
    std::string _path;                                        // 资源的具体路径
    std::string _suffix;                                      // 资源文件后缀
    std::string _version;                                     // 版本信息
    std::unordered_map<std::string, std::string> _headers_kv; // 请求报头各种属性键值
};

class HttpRespopnse
{

private:
public:
    HttpRespopnse()
        : _version(httpversion), _blank_line(base_sep)
    {
    }

    void AddCode(int code, const string &desc) // 状态码描述码
    {
        _status_code = code;
        _desc = desc;
    }

    void AddHeader(const string &k, const string &v)
    {
        _headers_kv[k] = v;
    }

    void AddBodyText(const string &body_text)
    {
        _resp_body_text = body_text;
    }

    string Serialize() // 序列化
    {
        // 1.构建状态行
        _status_line = _version + spacesep + std::to_string(_status_code) + spacesep + _desc + base_sep;

        // 2.构建应答报头
        for (auto &header : _headers_kv)
        {
            std::string header_line = header.first + line_sep + header.second + base_sep;
            _resp_headers.push_back(header_line);
        }

        // 3.空行和正文
        // 4.正式序列化
        string responsestr = _status_line;
        for (auto &line : _resp_headers)
        {
            responsestr += line;
        }
        responsestr += _blank_line;
        responsestr += _resp_body_text;
        return responsestr;
    }

private:
    // 响应的基本属性
    string _version;
    int _status_code;
    string _desc;
    std::unordered_map<std::string, std::string> _headers_kv;

    // 基本的响应格式
    string _status_line;
    std::vector<string> _resp_headers;
    string _blank_line;
    string _resp_body_text;
};

using func_t = std::function<HttpRespopnse(HttpRequest &)>; // 回调函数，传入一个封装好的请求，得到一个应答

class HttpServer
{
private:
    string GetFileContent(const string &path)
    {
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
        {
            return string();
        }
        in.seekg(0, in.end);       // 设置偏移量
        int filesize = in.tellg(); // 获得偏移量
        in.seekg(0, in.beg);

        string content;
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize); // 从in文件流里读取数据
        in.close();
        return content;
    }

public:
    HttpServer()
    {
        // 初始化
        _mime_type.insert(std::make_pair(".html", "text/html"));
        _mime_type.insert(std::make_pair(".jpg", "image/jpeg"));
        _mime_type.insert(std::make_pair(".png", "image/png"));
        _mime_type.insert(std::make_pair(".default", "text/html"));

        _code_to_desc.insert(std::make_pair(100, "Continue"));
        _code_to_desc.insert(std::make_pair(200, "OK"));
        _code_to_desc.insert(std::make_pair(201, "Created"));
        _code_to_desc.insert(std::make_pair(301, "Moved Permanently"));
        _code_to_desc.insert(std::make_pair(302, "Found"));
        _code_to_desc.insert(std::make_pair(404, "Not Found"));
    }
    ~HttpServer()
    {
    }
    // #define TEST
    string HandlerHttpRequest(string &reqstr) // req曾经被客户端序列化过的请求字符串
    {
#ifdef TEST // 条件编译，提供测试应答和非测试版本的应答
        cout << "--------------------------------------------------------" << endl;
        cout << reqstr << endl;

        string responsestr = "HTTP/1.1 200 OK\r\n";
        responsestr += "Content-Type: text/html\r\n";
        responsestr += "\r\n";
        responsestr += "<html><h1>hello Linux, hello bite!</h1></html>";
        return responsestr;
#else
        cout << "---------------------------------------------------------" << endl;
        cout << reqstr << endl; // 查看请求信息
        cout << "----------------------------------------------------------" << endl;
        HttpRequest req;
        HttpRespopnse resp;
        req.Deserialize(reqstr);
        if (req.Path() == "wwwroot/redir")
        {
            // 处理重定向
            string redir_path = "https://www.qq.com"; // 举例
            resp.AddCode(301, _code_to_desc[301]);
            resp.AddHeader("Location", redir_path);
        }
        else if (!req.GetResuestBody().empty())
        {
            if (IsServiceExists(req.Path()))
            {
                resp = _service_list[req.Path()](req);
            }
        }
        else
        {
            // 最基本的上层处理，处理静态资源
            string content = GetFileContent(req.Path());
            if (content.empty()) // 路径为空
            {
                content = GetFileContent("wwwroot/404.html"); // 加载资源
                resp.AddCode(404, _code_to_desc[404]);
                resp.AddHeader("Content-Length", to_string(content.size()));
                resp.AddHeader("Content-Type", _mime_type[".html"]);
                resp.AddBodyText(content);
            }
            else
            {
                resp.AddCode(200, _code_to_desc[200]);
                resp.AddHeader("Content-Length", std::to_string(content.size()));
                resp.AddHeader("Content-Type", _mime_type[req.Suffix()]);
                resp.AddHeader("Set-Cookie", "username=zhangsan");
                resp.AddBodyText(content);
            }
        }
        return resp.Serialize();
#endif
    }
    // 添加网络服务
    void InsertService(const string &servicename, func_t f)
    {
        string s = prefixpath + servicename;
        _service_list[s] = f;
    }

    bool IsServiceExists(const string &servicename)
    {
        if (!_service_list.count(servicename))
            return false;
        return true;
    }

private:
    std::unordered_map<string, string> _mime_type;    // 文件后缀与资源类型的映射
    std::unordered_map<int, string> _code_to_desc;    // 状态码和状态描述的映射
    std::unordered_map<string, func_t> _service_list; //
};